﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;

namespace CANMonitor
{
	/*------------兼容ZLG的数据类型---------------------------------*/

	//1.ZLGCAN系列接口卡信息的数据类型。
	public struct VCI_BOARD_INFO
	{
		public UInt16 hw_Version;	//硬件版本号，用16进制表示。比如0x0100表示V1.00。
		public UInt16 fw_Version;	//固件版本号，用16进制表示。比如0x0100表示V1.00。
		public UInt16 dr_Version;	//驱动程序版本号，用16进制表示。比如0x0100表示V1.00。
		public UInt16 in_Version;	//接口库版本号，用16进制表示。比如0x0100表示V1.00。
		public UInt16 irq_Num;		//保留参数。
		public byte can_Num;		//表示有几路CAN通道。
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
		public byte[] str_Serial_Num;	//此板卡的序列号。
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
		public byte[] str_hw_Type;		//硬件类型，比如“USBCAN V1.00”（注意：包括字符串结束符’\0’）
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
		public byte[] Reserved;			//系统保留。
	}

	/////////////////////////////////////////////////////
	//2.定义CAN信息帧的数据类型。
	unsafe public struct VCI_CAN_OBJ  //使用不安全代码
	{
		public uint ID;				  //帧ID。32位变量，数据格式为靠右对齐。详情请参照：《8.附件1：ID对齐方式.pdf》说
		public uint TimeStamp;        //设备收到某一帧的时间标识。时间标示从CAN卡上电开始计时，计时单位为0.1ms。
		public byte TimeFlag;         //是否使用时间标识，为1时TimeStamp有效，TimeFlag和TimeStamp只在此帧为接收帧时有意义。
		public byte SendType;         //发送帧类型。=0时为正常发送（发送失败会自动重发，重发最长时间为1.5-3秒）；
									  //            =1时为单次发送（只发送一次，不自动重发）；
									  //			=其它值, 无效。
									  //（二次开发，建议SendType=1，提高发送的响应速度）
		public byte RemoteFlag;       //是否是远程帧。=0时为为数据帧，=1时为远程帧
		public byte ExternFlag;       //是否是扩展帧。=0时为标准帧（11位ID），=1时为扩展帧（29位ID）。
		public byte DataLen;          //数据长度 DLC (<=8)，即CAN帧Data有几个字节。约束了后面Data[8]中的有效字节。
		public fixed byte Data[8];    //CAN帧的数据。由于CAN规定了最大是8个字节，所以这里预留了8个字节的空间，受 DataLen约束
		public fixed byte Reserved[3];//系统保留。

		unsafe public override string ToString()
		{
			StringBuilder ret = new StringBuilder();

			
			ret.Append(" ");

			int msec = (int)(TimeStamp % 10000);
			int sec = (int)((TimeStamp / 1000) % 60);
			int min = (int)(((TimeStamp / 1000) / 60) % 60);
			int hour = (int)((((TimeStamp / 1000) / 60) / 60) % 60);
			ret.Append(string.Format("{0:D2}:{1:D2}:{2:D2}.{3:D4}\t", hour, min, sec, msec));

			ret.Append(string.Format("{0:X}\t", ID));

			ret.Append("Rx ");
			ret.Append(ExternFlag == 0 ? "ext " : "std ");
			ret.Append(RemoteFlag == 0 ? "rtr " : "dat ");
			ret.Append(DataLen.ToString());

			fixed (byte* pdata = Data)
			{
				for (int i = 0; i < DataLen; i++)
				{
					ret.Append(string.Format(" | {0:X02} ", pdata[i]));
				}
			}

			return ret.ToString();
		}

		unsafe public string[] ToStringArray()
		{
			string[] ret = new string[7];

			int msec = (int)(TimeStamp % 10000);
			int sec = (int)((TimeStamp / 1000) % 60);
			int min = (int)(((TimeStamp / 1000) / 60) % 60);
			int hour = (int)((((TimeStamp / 1000) / 60) / 60) % 60);
			ret[0] = string.Format("{0:D2}:{1:D2}:{2:D2}.{3:D4}", hour, min, sec, msec);
			ret[1] = string.Format("{0:X}", ID);
			ret[2] = "rx";
			ret[3] = ExternFlag == 0 ? "std " : "ext ";
			ret[4] = RemoteFlag == 0 ? "dat " : "rtr ";
			ret[5] = DataLen.ToString();

			StringBuilder data_str = new StringBuilder();
			fixed (byte* pdata = Data)
			{
				for (int i = 0; i < DataLen; i++)
				{
					data_str.Append(string.Format("{0:X02} ", pdata[i]));
				}
			}
			ret[6] = data_str.ToString();

			return ret;
		}

		unsafe public CanMsg ToCanMsg()
		{
			try
			{
				UInt32 _Tick = this.TimeStamp;
				UInt32 _Id = this.ID;

				bool _beTx = (this.SendType != 0x00);
				bool _beExtern = (this.ExternFlag != 0x00);
				bool _beRemote = (this.RemoteFlag != 0x00);
				byte _Dlc = this.DataLen;

				_Id &= 0x1FFFFFFF;
				if (_beTx) _Id |= 0x80000000;
				if (_beExtern) _Id |= 0x40000000;
				if (_beRemote) _Id |= 0x20000000;

				byte[] _Data = new byte[_Dlc];
				fixed (byte* pData = this.Data)
				{
					for (int i = 0; i < _Dlc; i++)
					{
						_Data[i] = pData[i];
					}
				}

				// 生成CanMsg对象
				return CanMsg.Parse(_Tick, _Id, _Data, _beTx, _beExtern, _beRemote);
			}
			catch
			{
				return null;
			}
		}

		public static VCI_CAN_OBJ Parse(CanMsg msg)
		{
			VCI_CAN_OBJ ret = new VCI_CAN_OBJ();
			ret.ID = msg.mID;
			ret.TimeStamp=0;       //时间标识
			ret.TimeFlag = 0;      //是否使用时间标识
			//ret.SendType;          //发送标志。保留，未用
			ret.RemoteFlag= (byte)(msg.mIsRtr ? 0x01:0x00); //是否是远程帧
			ret.ExternFlag= (byte)(msg.mIsExt ? 0x01:0x00); //是否是扩展帧
			ret.DataLen = (byte)(msg.mData.Length);			//数据长度
			for (int i = 0; i < ret.DataLen; i++)
			{
				ret.Data[i] = msg.mData[i];//数据
			}
			//ret.Reserved[3];//保留位

			return ret;
		}

	}

	//3.定义初始化CAN的数据类型
	public struct VCI_INIT_CONFIG
	{
		public UInt32 AccCode;	//验收码。SJA1000的帧过滤验收码。对经过屏蔽码过滤为“有关位”进行匹配，全部匹配成功后，此帧可以被接收。否则不接收。详见VCI_InitCAN。
		public UInt32 AccMask;	//屏蔽码。SJA1000的帧过滤屏蔽码。对接收的CAN帧ID进行过滤，对应位为0的是“有关位”，对应位为1的是“无关位”。屏蔽码推荐设置为0xFFFFFFFF，即全部接收。
		public UInt32 Reserved;	//保留。
		public byte Filter;   //滤波方式: 0或1接收所有帧。2标准帧滤波，3是扩展帧滤波。
		private byte Timing0;  //波特率定时器 0（BTR0）波特率参数，具体配置，请查看二次开发库函数说明书。
		private byte Timing1;  //波特率定时器 1（BTR1）
		public byte Mode;     //模式。=0表示正常模式（相当于正常节点），
							  //      =1表示只听模式（只接收，不影响总线），
							  //      =2表示自发自收模式（环回模式）

		public CanBaud Baud
		{
			set
			{
				this.Timing0 = (byte)( ((uint)value >> 8) & 0xFF);
				this.Timing1 = (byte)( ((uint)value >> 0) & 0xFF);
			}
			get
			{
				uint ret = (uint)(((uint)this.Timing0 << 8) | this.Timing1);
				return (CanBaud)ret;
			}
		}
	}

	public enum CanBaud : uint  //波特率参数，具体配置如下
	{							// CAN波特率   Timing0(BTR0)   Timing1(BTR1)
		Baud_10Kbps = 0x311C,   // 10 Kbps     0x31            0x1C 
		Baud_20Kbps = 0x181C,   // 20 Kbps     0x18            0x1C 
		Baud_40Kbps = 0x87FF,   // 40 Kbps     0x87            0xFF 
		Baud_50Kbps = 0x091C,   // 50 Kbps     0x09            0x1C 
		Baud_80Kbps = 0x83FF,   // 80 Kbps     0x83            0xFF 
		Baud_100Kbps = 0x041C,  // 100 Kbps    0x04            0x1C 
		Baud_125Kbps = 0x031C,  // 125 Kbps    0x03            0x1C 
		Baud_200Kbps = 0x81FA,  // 200 Kbps    0x81            0xFA 
		Baud_250Kbps = 0x011C,  // 250 Kbps    0x01            0x1C 
		Baud_400Kbps = 0x80FA,  // 400 Kbps    0x80            0xFA 
		Baud_500Kbps = 0x001C,  // 500 Kbps    0x00            0x1C 
		Baud_666Kbps = 0x80B6,  // 666 Kbps    0x80            0xB6 
		Baud_800Kbps = 0x0016,  // 800 Kbps    0x00            0x16 
		Baud_1000Kbps = 0x0014, // 1000 Kbps   0x00            0x14 
		Baud_33_33Kbps = 0x096F,// 33.33 Kbps  0x09            0x6F 
		Baud_66_66Kbps = 0x046F,// 66.66 Kbps  0x04            0x6F 
		Baud_83_33Kbps = 0x036F,// 83.33 Kbps  0x03            0x6F 
	}

	/*------------其他数据结构描述---------------------------------*/
	//4.USB-CAN总线适配器板卡信息的数据类型1，该类型为VCI_FindUsbDevice函数的返回参数。
	public struct VCI_BOARD_INFO1
	{
		public UInt16 hw_Version;
		public UInt16 fw_Version;
		public UInt16 dr_Version;
		public UInt16 in_Version;
		public UInt16 irq_Num;
		public byte can_Num;
		public byte Reserved; //低层不用, 上层在调用find时,用这个记录device_id
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
		public byte[] str_Serial_Num;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
		public byte[] str_hw_Type;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
		public byte[] str_Usb_Serial;


		public override string ToString()
		{
			StringBuilder ret = new StringBuilder();
			ret.Append("device_Index:" + Reserved.ToString() + "\r\n"); 
			ret.Append("can_Num:");
			ret.Append(can_Num.ToString());
			ret.Append("\r\ndr_Version:");
			ret.Append(dr_Version.ToString("X"));
			ret.Append("\r\nfw_Version:");
			ret.Append(fw_Version.ToString("X"));
			ret.Append("\r\nhw_Version:");
			ret.Append(hw_Version.ToString("X"));
			ret.Append("\r\nin_Version:");
			ret.Append(in_Version.ToString("X"));
			ret.Append("\r\nirq_Num:");
			ret.Append(irq_Num.ToString());

			ret.Append("\r\nstr_hw_Type:");
			for (int i = 0; i < str_hw_Type.Length; i++)
			{
				if (str_hw_Type[i] == 0x00)
					break;
				ret.Append((char)str_hw_Type[i]);
			}

			ret.Append("\r\nstr_Serial_Num:");
			for (int i = 0; i < str_Serial_Num.Length; i++)
			{
				if (str_Serial_Num[i] == 0x00)
					break;
				ret.Append((char)str_Serial_Num[i]);
			}
			ret.Append("\r\n");

			return ret.ToString();
		}

		public string ToShortString()
		{
			StringBuilder ret = new StringBuilder();
			ret.Append(Reserved.ToString());
			ret.Append(" ");
			for (int i = 0; i < str_Serial_Num.Length; i++)
			{
				if (str_Serial_Num[i] == 0x00)
					break;
				ret.Append((char)str_Serial_Num[i]);
			}
			return ret.ToString();
		}

		public string Get_SN()
		{
			StringBuilder ret = new StringBuilder();
			for (int i = 0; i < str_Serial_Num.Length; i++)
			{
				if (str_Serial_Num[i] == 0x00)
					break;
				ret.Append((char)str_Serial_Num[i]);
			}
			return ret.ToString();
		}
		public int Get_Index()
		{
			return (int)Reserved;
		}
	}

	/*------------数据结构描述完成---------------------------------*/

	public struct CHGDESIPANDPORT
	{
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
		public byte[] szpwd;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
		public byte[] szdesip;
		public Int32 desport;

		public void Init()
		{
			szpwd = new byte[10];
			szdesip = new byte[20];
		}
	}

	public enum VCI_OptionResult
	{
		VCI_Failed,
		VCI_Success,
		VCI_NoDevice,	// 除了操作成功 和 操作失败，其它均认为无设备(掉线)
	}


	public class CanAlyst_II	// 一个 CanAlyst_II盒，有两个Can收发器
	{
		
		#region DLL接口函数封装。为避免混乱：类其它函数只能调用 DLL_xxx函数，不可调用 VCI_xxx函数

		/*------------ a.接口函数约定---------------------------------*/

		/*
		 *  DeviceType，设备类型:
		 *	固定为4，表示设备为USBCAN_2A、USBCAN_2C 或 CANalyst_II
		 *
		 *	DeviceInd，设备索引:
		 *	只有一个USB_CAN适配器时，索引号为0；这时再插一个USB_CAN适配器，则其索引为1.以此类推
		 *
		 *	CANInd, CAN通道索引：
		 *	对应USB_CAN适配器的CAN通道号，CAN1的通道号为0，CAN2的通道号为1
		 *
		 *	返回值：
		 *	1:表示操作成功。  0:表示操作失败。 -1：表示USB_CAN设备不存在，或USB掉线。
		 *	
		 */

		/*------------ b.兼容ZLG的函数描述---------------------------------*/
		[DllImport("controlcan.dll")]
		static extern UInt32 VCI_OpenDevice(UInt32 DeviceType, Int32 DeviceInd, UInt32 Reserved);
		private VCI_OptionResult DLL_OpenDevice()
		{
			UInt32 result = VCI_OpenDevice(m_device_type, m_device_index, 0);

			if (result == 1)  return VCI_OptionResult.VCI_Success;
			if (result == 0)  return VCI_OptionResult.VCI_Failed;
			return VCI_OptionResult.VCI_NoDevice;
		}

		[DllImport("controlcan.dll")]
		static extern UInt32 VCI_CloseDevice(UInt32 DeviceType, Int32 DeviceInd);
		private VCI_OptionResult DLL_CloseDevice()
		{
			UInt32 result = VCI_CloseDevice(m_device_type, m_device_index);

			if (result == 1) return VCI_OptionResult.VCI_Success;
			if (result == 0) return VCI_OptionResult.VCI_Failed;
			return VCI_OptionResult.VCI_NoDevice;
		}

		[DllImport("controlcan.dll")]
		static extern UInt32 VCI_InitCAN(UInt32 DeviceType, Int32 DeviceInd, Int32 CANInd, ref VCI_INIT_CONFIG pInitConfig);
		private VCI_OptionResult DLL_InitCAN(Int32 CANInd, ref VCI_INIT_CONFIG pInitConfig)
		{
			UInt32 result = VCI_InitCAN(m_device_type, m_device_index, CANInd, ref pInitConfig);

			if (result == 1) return VCI_OptionResult.VCI_Success;
			if (result == 0) return VCI_OptionResult.VCI_Failed;
			return VCI_OptionResult.VCI_NoDevice;
		}


		[DllImport("controlcan.dll")]
		static extern UInt32 VCI_ReadBoardInfo(UInt32 DeviceType, Int32 DeviceInd, ref VCI_BOARD_INFO pInfo);
		private VCI_OptionResult DLL_ReadBoardInfo(ref VCI_BOARD_INFO pInfo)
		{
			UInt32 result = VCI_ReadBoardInfo(m_device_type, m_device_index, ref pInfo);

			if (result == 1) return VCI_OptionResult.VCI_Success;
			if (result == 0) return VCI_OptionResult.VCI_Failed;
			return VCI_OptionResult.VCI_NoDevice;
		}

		//[DllImport("controlcan.dll")]
		//static extern UInt32 VCI_GetReceiveNum(UInt32 DeviceType, Int32 DeviceInd, Int32 CANInd);
		////此函数用以获取指定CAN通道的接收缓冲区中，接收到但尚未被读取的帧数量。主要用途是配合VCI_Receive使用，即缓冲区有数据，再接收。
		////实际应用中，用户可以忽略该函数，直接循环调用VCI_Receive，可以节约PC系统资源，提高程序效率。
		//private VCI_OptionResult DLL_GetReceiveNum(Int32 CANInd, ref UInt32 rec_num)
		//{
		//    UInt32 result = VCI_GetReceiveNum(m_device_type, m_device_index, CANInd);

		//    if (result < 2000)
		//    {
		//        rec_num = result;
		//        return VCI_OptionResult.VCI_Success;
		//    }

		//    return VCI_OptionResult.VCI_NoDevice;
		//}


		[DllImport("controlcan.dll")]
		static extern UInt32 VCI_ClearBuffer(UInt32 DeviceType, Int32 DeviceInd, Int32 CANInd);
		private VCI_OptionResult DLL_ClearBuffer(Int32 CANInd)
		{
			UInt32 result = VCI_ClearBuffer(m_device_type, m_device_index, CANInd);

			if (result == 1) return VCI_OptionResult.VCI_Success;
			if (result == 0) return VCI_OptionResult.VCI_Failed;
			return VCI_OptionResult.VCI_NoDevice;
		}

		[DllImport("controlcan.dll")]
		static extern UInt32 VCI_StartCAN(UInt32 DeviceType, Int32 DeviceInd, Int32 CANInd);
		private VCI_OptionResult DLL_StartCAN(Int32 CANInd)
		{
			UInt32 result = VCI_StartCAN(m_device_type, m_device_index, CANInd);

			if (result == 1) return VCI_OptionResult.VCI_Success;
			if (result == 0) return VCI_OptionResult.VCI_Failed;
			return VCI_OptionResult.VCI_NoDevice;
		}

		[DllImport("controlcan.dll")]
		static extern UInt32 VCI_ResetCAN(UInt32 DeviceType, Int32 DeviceInd, Int32 CANInd);
		private VCI_OptionResult DLL_ResetCAN(Int32 CANInd)
		{
			UInt32 result = VCI_ResetCAN(m_device_type, m_device_index, CANInd);

			if (result == 1) return VCI_OptionResult.VCI_Success;
			if (result == 0) return VCI_OptionResult.VCI_Failed;
			return VCI_OptionResult.VCI_NoDevice;
		}

		[DllImport("controlcan.dll")]
		static extern UInt32 VCI_Transmit(UInt32 DeviceType, Int32 DeviceInd, Int32 CANInd, ref VCI_CAN_OBJ pSend, Int32 Len);
		//Len 要发送的帧结构体数组的长度（发送的帧数量）。最大为1000，建议设为1，每次发送单帧，以提高发送效率
		private VCI_OptionResult DLL_Transmit(Int32 CANInd, ref VCI_CAN_OBJ pSend, Int32 Len)
		{
			UInt32 result = VCI_Transmit(m_device_type, m_device_index, CANInd, ref pSend, Len);

			if (result == 1) return VCI_OptionResult.VCI_Success;
			if (result == 0) return VCI_OptionResult.VCI_Failed;
			return VCI_OptionResult.VCI_NoDevice;
		}


		[DllImport("controlcan.dll")]
		static extern Int32 VCI_Receive(UInt32 DeviceType, Int32 DeviceInd, Int32 CANInd, ref VCI_CAN_OBJ pReceive, UInt32 Len, UInt32 WaitTime);
		//Len: 用来接收的帧结构体数组的长度（本次接收的最大帧数，实际返回值小于等于这个值）。
		//该值为所提供的存储空间大小，适配器中为每个通道设置了2000帧的接收缓存区，
		//用户根据自身系统和工作环境需求，在1到2000之间选取适当的接收数组长度。
		//一般pReceive数组大小与Len都设置大于2000，如：2500为宜，可有效防止数据溢出导致地址冲突。
		//同时每隔30ms调用一次VCI_Receive为宜。（在满足应用的时效性情况下，尽量降低调用VCI_Receive的频率，
		//只要保证内部缓存不溢出，每次读取并处理更多帧，可以提高运行效率。）
		//WaitTime: 保留参数。
		private VCI_CAN_OBJ[] pReceive = new VCI_CAN_OBJ[2500];
		private List<VCI_CAN_OBJ> DLL_Receive(Int32 CANInd)
		{
			Int32 result = VCI_Receive(m_device_type, m_device_index, CANInd, ref pReceive[0], 2500, 0);
			//返回实际读取的帧数，=-1表示USB-CAN设备不存在或USB掉线。
			if ((0 <= result) && (result < 2500))
			{
				List<VCI_CAN_OBJ> ret = new List<VCI_CAN_OBJ>();
				for (Int32 i = 0; i < result; i++)
				{
					ret.Add(pReceive[i]);
				}
				return ret;
			}
			return null; //报告上层设备不存在 或 usb掉线
		}

		/*------------ c.其他函数描述---------------------------------*/

		[DllImport("controlcan.dll")]
		static extern UInt32 VCI_ConnectDevice(UInt32 DeviceType, Int32 DeviceInd);
		private VCI_OptionResult DLL_ConnectDevice()
		{
			UInt32 result = VCI_ConnectDevice(m_device_type, m_device_index);

			if (result == 1) return VCI_OptionResult.VCI_Success;
			if (result == 0) return VCI_OptionResult.VCI_Failed;
			return VCI_OptionResult.VCI_NoDevice;
		}


		[DllImport("controlcan.dll")]
		static extern UInt32 VCI_UsbDeviceReset(UInt32 DevType, Int32 DevIndex, UInt32 Reserved);
		private VCI_OptionResult DLL_UsbDeviceReset()
		{
			UInt32 result = VCI_UsbDeviceReset(m_device_type, m_device_index, 0);

			if (result == 1) return VCI_OptionResult.VCI_Success;
			if (result == 0) return VCI_OptionResult.VCI_Failed;
			return VCI_OptionResult.VCI_NoDevice;
		}


		[DllImport("controlcan.dll")]
		static extern UInt32 VCI_FindUsbDevice(ref VCI_BOARD_INFO1 pInfo);
		static private List<VCI_BOARD_INFO1> DLL_FindUsbDevice()
		{
			VCI_BOARD_INFO1[] info_arr = new VCI_BOARD_INFO1[4];// 在同一计算机中，可同时支持4台USB_CAN设备。是否会越界?

			UInt32 count = VCI_FindUsbDevice(ref info_arr[0]);
			if (count > 0)
			{
				List<VCI_BOARD_INFO1> info_list = new List<VCI_BOARD_INFO1>();
				for (UInt32 i = 0; i < count; i++)
				{
					info_arr[i].Reserved = (byte)i;
					info_list.Add(info_arr[i]);
				}
				return info_list;
			}

			return null;
		}

		/*------------ d.函数描述结束---------------------------------*/
		#endregion


		// -------------------------------------------------------------------------------------------------------
		#region 0. 类静态操作，诸如查询各个Device信息 等

		static public List<VCI_BOARD_INFO1> FindUsbDevice()
		{
			return DLL_FindUsbDevice();
		}

		static public string[] GetPortNames()
		{
			List<VCI_BOARD_INFO1> list = FindUsbDevice();
			if (list != null)
			{
				string[] ret = new string[list.Count];
				for (int i = 0; i < ret.Length; i++)
				{
					ret[i] = list[i].Get_SN();
				}
				return ret;
			}
			return new string[0];
		}

		#endregion


		// -------------------------------------------------------------------------------------------------------
		#region 1. Device 的操作，包括断线重连管理

		private const UInt32 m_device_type = 4;
		private Int32 m_device_index;

		private bool m_device_IsOpen = false;
		private Timer m_100ms_Timer;


		public CanAlyst_II()
		{
			m_100ms_Timer = new Timer(Device_100msTimer_Tick, null, 0, 100);
		}

		public void Device_Open(Int32 device_index)
		{
			if (m_device_IsOpen == true)
				return;

			if (DLL_OpenDevice() == VCI_OptionResult.VCI_Success)
			{

				m_device_index = device_index;
				m_device_IsOpen = true;
			}
			else
			{
				throw new Exception("打开CAN盒失败, id:" + device_index.ToString());
			}
		}

		public bool Device_ReOpen()
		{
			if (m_device_IsOpen == false)
				return true;

			if (DLL_OpenDevice() == VCI_OptionResult.VCI_Success)
			{
				return true;
			}

			return false;
		}

		public bool Device_Close()
		{
			if (m_device_IsOpen == false)
				return true;

			if (DLL_CloseDevice() == VCI_OptionResult.VCI_Success)
			{
				m_device_IsOpen = false;
				return true;
			}
			return false;
		}

		public bool Device_Reset()
		{
			if (m_device_IsOpen == false)
				return false;

			if (DLL_UsbDeviceReset() == VCI_OptionResult.VCI_Success)
			{
				m_device_IsOpen = false;
				return true;
			}
			return false;
		}

		public bool ReadBoardInfo(ref VCI_BOARD_INFO info)
		{
			if (DLL_ReadBoardInfo(ref info) == VCI_OptionResult.VCI_Success)
				return true;

			return false;
		}

		private void Device_100msTimer_Tick(object o)
		{
			if (m_device_IsOpen == false)
				return;

			// 驱动CAN的接收
			VCI_OptionResult result0 = CANx_Read_ProtBuffer(0);
			VCI_OptionResult result1 = CANx_Read_ProtBuffer(1);
			
			//断线重连
			if (result0 == VCI_OptionResult.VCI_NoDevice || result1 == VCI_OptionResult.VCI_NoDevice)
			{
				if (DLL_ConnectDevice() == VCI_OptionResult.VCI_Success)
				{
					Device_ReOpen();
					CANx_ReStart(0);
					CANx_ReStart(1);
				}
			}
		}



		public bool Device_IsOpen()
		{
			return DLL_ConnectDevice() == VCI_OptionResult.VCI_Success;
		}

		#endregion


		// -------------------------------------------------------------------------------------------------------
		#region 2. 端口 的操作

		private object[] m_CANx_Start_Object = {new object(), new object()};

		private bool[] m_CANx_Started = {false, false};
		private VCI_INIT_CONFIG[] m_Canx_config = { new VCI_INIT_CONFIG(), new VCI_INIT_CONFIG()};

		private List<CanMsg>[] m_CANx_RxBuff = { new List<CanMsg>(), new List<CanMsg>() };

		public enum CanMode	:uint
		{
			Normal		= 0,//正常模式
			Silent		= 1,//监听模式
			LoopBack	= 2,//环回自测模式
		}
		

		public void CANx_Start(int index, CanMode mode, CanBaud baud)
		{
			if (m_device_IsOpen == false)
				throw new Exception("devie还未打开");

			lock (m_CANx_Start_Object[index])
			{
				VCI_INIT_CONFIG config = new VCI_INIT_CONFIG();

				// 接收所有帧
				config.AccCode = 0x00000000;
				config.AccMask = 0xFFFFFFFF;
				config.Filter = 0;

				config.Mode = (byte)mode;
				config.Baud = baud;

				if (DLL_InitCAN(index, ref config) != VCI_OptionResult.VCI_Success)
					throw new Exception("写入配置失败");

				if (DLL_StartCAN(index) != VCI_OptionResult.VCI_Success)
					throw new Exception("打开端口失败");

				m_Canx_config[index] = config;
				m_CANx_Started[index] = true;
			}
		}

		private void CANx_ReStart(int index)
		{
			if (m_CANx_Started[index] == false)
				return;

			lock (m_CANx_Start_Object[index])
			{
				if (DLL_InitCAN(index, ref m_Canx_config[index]) != VCI_OptionResult.VCI_Success)
					return;

				if (DLL_StartCAN(index) != VCI_OptionResult.VCI_Success)
					return;
			}
		}

		public bool CANx_IsStart(int index)
		{
			return m_CANx_Started[index];
		}

		public bool CANx_Stop(int index)
		{
			if (m_device_IsOpen == false)
				return false;

			if (DLL_ResetCAN(index) == VCI_OptionResult.VCI_Success)
			{
				m_CANx_Started[index] = false;
				return true;
			}

			return false;
		}

		public bool CANx_Clear_PortBuffer(int index)
		{
			if (m_device_IsOpen == false)
				return false;

			if (DLL_ClearBuffer(index) == VCI_OptionResult.VCI_Success)
			{
				return true;
			}
			return false;
		}


		public List<CanMsg> CANx_ReadMsg(int index)
		{
			List<CanMsg> list = null;

			lock (m_CANx_RxBuff[index])
			{
				list = m_CANx_RxBuff[index];
				m_CANx_RxBuff[index] = new List<CanMsg>();
			}

			return list;
		}

		public bool CANx_TransMsg(int index, ref CanMsg msg)
		{
			VCI_CAN_OBJ can_obj = VCI_CAN_OBJ.Parse(msg);
			VCI_OptionResult ret = DLL_Transmit(index, ref can_obj, 1);
			
			return (ret == VCI_OptionResult.VCI_Success);
		}

		private VCI_CAN_OBJ[] obj_list_tx = new VCI_CAN_OBJ[1000];// 设备驱驱动最多传入1000条,高速收发时推荐值为48
		public bool CANx_TransMsg(int index, ref List<CanMsg> msg)
		{
			if (msg.Count > 48) return false;
			int len = msg.Count;
			for (int i = 0; i < len; i++)
			{
				obj_list_tx[i] = VCI_CAN_OBJ.Parse(msg[i]);
			}
			VCI_OptionResult ret = DLL_Transmit(index, ref obj_list_tx[0], len);

			return (ret == VCI_OptionResult.VCI_Success);
		}


		//内部函数: 读取硬件缓存, 每隔30ms调用一次为宜
		private VCI_OptionResult CANx_Read_ProtBuffer(int index)
		{
			if (m_CANx_Started[index] == false)
				return VCI_OptionResult.VCI_Success; //商品未打开, 认为连接正常, 不要尝试重连了

			List<VCI_CAN_OBJ> ret = DLL_Receive(index);
			if (ret != null)
			{
				List<CanMsg> ret_msg = new List<CanMsg>();
				foreach (VCI_CAN_OBJ item in ret)
				{
					ret_msg.Add(item.ToCanMsg());
				}
				lock (m_CANx_RxBuff[index]) //缓存读到的消息
				{
					m_CANx_RxBuff[index].AddRange(ret_msg);
				}
				return VCI_OptionResult.VCI_Success;
			}
			return VCI_OptionResult.VCI_NoDevice;
		}

		#endregion
	}


}
